package com.wrupple.muba.catalogs.client.module.services.logic.impl;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArrayString;
import com.google.inject.Inject;
import com.wrupple.muba.catalogs.client.channels.CatalogDescriptionChannel;
import com.wrupple.muba.catalogs.client.channels.CatalogListingChannel;
import com.wrupple.muba.catalogs.client.module.services.logic.CatalogDescriptionService;
import com.wrupple.muba.common.client.application.DataCallback;
import com.wrupple.muba.common.shared.StateTransition;
import com.wrupple.vegetate.client.VegetateConstants;
import com.wrupple.vegetate.domain.CatalogDescriptor;

public class CatalogDescriptionServiceImpl implements CatalogDescriptionService {
	static {
		 cache = new HashMap<String, CatalogDescriptor>();
	}
	static class LoadCatalogDescriptor extends DataCallback<CatalogDescriptor> {
		private StateTransition<CatalogDescriptor> onDone;
		private String catalogId;

		public LoadCatalogDescriptor(StateTransition<CatalogDescriptor> onDone, String catalogId) {
			super();
			this.onDone = onDone;
			this.catalogId = catalogId;
		}

		@Override
		public void execute() {
			if (result == null) {
				//StaticDesktopAccess.addUIError(constants.catalogLoadError());
				return;
			}
			GWT.log("catalog with id " + catalogId + " received", null);
			cache.put(catalogId, result);
			onDone.setResult(result);
			onDone.execute();
		}
	}

	private class OnCatalogNamesReceived extends DataCallback<Set<String>> {
		DataCallback<Set<String>> callback;

		public OnCatalogNamesReceived(DataCallback<Set<String>> callback) {
			this.callback = callback;
		}

		@Override
		public void execute() {
			catalogNames = result;
			callback.setResult(result);
			callback.execute();
		}

	}
	
	private class ConvertJsArray extends DataCallback<JsArrayString>{
		DataCallback<Set<String>> callback;
		
		public ConvertJsArray(DataCallback<Set<String>> callback) {
			super();
			this.callback = callback;
		}

		@Override
		public void execute() {
			LinkedHashSet<String> regreso = new LinkedHashSet<String>();
			String s;
			for(int i = 0 ; i < result.length() ; i++){
				s = result.get(i);
				regreso.add(s);
			}
			callback.setResultAndFinish(regreso);
		}
		
	}

	/**
	 * names of all registered catalogs
	 */
	private static Set<String> catalogNames;

	/**
	 * convinience storage for CatalogDescriptors fetched from the server
	 */
	private static Map<String, CatalogDescriptor> cache;
	

	/**
	 * Static UI Strings
	 */
	private static VegetateConstants constants;
	private CatalogListingChannel listingChannel;
	private static CatalogDescriptionChannel descriptionChannel;
	@Inject
	public CatalogDescriptionServiceImpl(VegetateConstants constants, CatalogListingChannel listingChannel,CatalogDescriptionChannel description) {
		super();
		this.listingChannel=listingChannel;
		this.descriptionChannel=description;
		CatalogDescriptionServiceImpl.constants = constants;
	}

	@Override
	public void loadCatalogDescriptor(final String catalogId, final StateTransition<CatalogDescriptor> onDone) {
		assert catalogId!=null:"Attemped to load the descriptor of a null identifier";
		assert onDone != null : "Attempted to load a catalog descriptor but no load callback was provided";
		if (cache.containsKey(catalogId)) {
			onDone.setResult(cache.get(catalogId));
			onDone.execute();
		} else {
			DataCallback<CatalogDescriptor> callback = new LoadCatalogDescriptor(onDone, catalogId);
			
			descriptionChannel.send(null,	callback, LIST_ACTION_TOKEN,catalogId);
		}
	}

	@Override
	public CatalogDescriptor loadFromCache(String catalog) {
		return cache.get(catalog);
	}

	@Override
	public void loadCatalogNames(DataCallback<Set<String>> callback) {
		if (catalogNames == null) {
			requestCatalogIds(new OnCatalogNamesReceived(callback));
		} else {
			callback.setResult(catalogNames);
			callback.execute();
		}
	}
	
	
	public static String nameField(String catalogid){
		return cache.get(catalogid).getDescriptiveField();
	}
	
	public static String idField(String catalogid){
		return cache.get(catalogid).getKeyField();
	}

	protected void requestCatalogIds(DataCallback<Set<String>> callback) {
		listingChannel.send(null, new ConvertJsArray(callback), LIST_ACTION_TOKEN);

	}

}
